import sys
import random
import Util
import Vector
import Ship
import copy
import Config
import Configurable
import G
import Behavior
import ConfigParser
import math

random.seed()

class Formation(Configurable.Configurable):
   runtime_vars = ('order',)

   __slots__ = ('ship_type',
                'count',
                'startx',
                'starty',
                'delx',
                'dely',
                'destx',
                'desty',
                'when',
                'move_behavior',
                'fire_behavior',
                'ship_args') + runtime_vars
   
   def __init__(self, name, ship_type, order=0, count=1, when=0, move_behavior=None, fire_behavior=None,
                startx=Config.width/2, starty=-200,
                destx=None, desty=None, description="", **ship_args):
      Configurable.Configurable.__init__(self, locals())
      self.order = order
      self.count = count
      self.startx = startx
      self.starty = starty
      if destx is None:
         self.destx = startx
      else:
         self.destx = destx
      if desty is None:
         self.desty = starty
      else:
         self.desty = desty
      self.delx = self.destx - self.startx
      self.dely = self.desty - self.starty
      if not isinstance(when, int) and not isinstance(when, float):
         self.when = 0
      else:
         self.when = when
      self.ship_type = G.ships[ship_type]
   
   @classmethod
   def from_file(cls, items):
      formation_type = None
      for key, val in items:
         if key == 'formation':
            formation_type = eval(val)
      vars = formation_type.config_vars()
      form_vals = dict()
      wave_vals = dict()
      for key, val in items:
         if key in vars:
            form_vals[key] = Util.str_convert(val)
         else:
            wave_vals[key] = Util.str_convert(val)
      for b in ('move_behavior', 'fire_behavior'):
         if b in form_vals.keys():
            behavior_type = eval("Behavior." + form_vals[b])
            behavior_vars = behavior_type.config_vars()
            behavior_values = [['name', form_vals[b]]]
            for k in wave_vals.keys():
               if k in behavior_vars:
                  behavior_values.append((k, wave_vals[k]))
            form_vals[b] = behavior_type.from_file(behavior_values)
      formation_type.check_missing(form_vals)
      form_vals['type'] = formation_type
      form_vals.update(wave_vals)
      return form_vals
   
   def spawn(self):
      abstract

class line(Formation):
   __slots__ = ('length',
                'angle')
   
   def __init__(self, length=8*Config.width/10, angle=0.0, **args):
      Configurable.Configurable.__init__(self, locals())
      Formation.__init__(self, **args)
      while self.angle > 90:
         self.angle -= 90
      while self.angle < -90:
         self.angle += 90
      self.angle *= math.pi / 180
   
   def spawn(self):
      start = (int(self.startx - math.cos(self.angle) * self.length/2),
               int(self.starty + math.sin(self.angle) * self.length/2))
      end = (int(self.startx + math.cos(self.angle) * self.length/2),
             int(self.starty - math.sin(self.angle) * self.length/2))
      if self.count > 1:
         d = self.count - 1
      else:
         d = 1
      for i in range(0, self.count):
         p = (start[0] + i * (end[0] - start[0]) / d,
              start[1] + i * (end[1] - start[1]) / d)
         Ship.spawn(self.ship_type, p, (p[0] + self.delx, p[1] + self.dely),
                           self.move_behavior, self.fire_behavior, **self.ship_args)

class grid(Formation):
   __slots__ = ('dims',
                'ship_dims',
                'angle')
   
   def __init__(self, dims=(8*Config.width/10, Config.height/2),
                ship_dims=(0,0), angle=0.0, **args):
      args['count'] = ship_dims[0] * ship_dims[1]
      Configurable.Configurable.__init__(self, locals())
      Formation.__init__(self, **args)
      while self.angle > 90:
         self.angle -= 90
      while self.angle < -90:
         self.angle += 90
      self.angle *= -1 * math.pi / 180
   
   def spawn(self):
      diag = math.sqrt(self.dims[0]**2 + self.dims[1]**2) / 2
      ang = math.atan2(self.dims[1]/2, self.dims[0]/2)
      start = (int(self.startx + math.cos(self.angle + ang + math.pi) * diag),
               int(self.starty + math.sin(self.angle + ang + math.pi) * diag))
      if self.ship_dims[0] > 1:
         x_d = self.ship_dims[0]
      else:
         x_d = 1
      if self.ship_dims[1] > 1:
         y_d = self.ship_dims[1]
      else:
         y_d = 1
      x_s = self.dims[0] / x_d
      y_s = self.dims[1] / y_d
      x_space = (int(x_s * math.cos(self.angle)),
                 int(x_s * math.sin(self.angle)))
      y_space = (-1 * int(y_s * math.sin(self.angle)),
                 int(y_s * math.cos(self.angle)))
      for i in range(0, self.ship_dims[0]):
         for j in range(0, self.ship_dims[1]):
            p = (start[0] + i * x_space[0] + j * y_space[0],
                 start[1] + i * x_space[1] + j * y_space[1])
            Ship.spawn(self.ship_type, p, (p[0] + self.delx, p[1] + self.dely),
                       self.move_behavior, self.fire_behavior, **self.ship_args)

class checkerboard(Formation):
   __slots__ = ('dims',
                'ship_dims',
                'angle')
   
   def __init__(self, dims=(8*Config.width/10, Config.height/2),
                ship_dims=(0,0), angle=0.0, **args):
      args['count'] = ship_dims[0] * ship_dims[1]
      Configurable.Configurable.__init__(self, locals())
      Formation.__init__(self, **args)
      while self.angle > 90:
         self.angle -= 90
      while self.angle < -90:
         self.angle += 90
      self.angle *= -1 * math.pi / 180
   
   def spawn(self):
      diag = math.sqrt(self.dims[0]**2 + self.dims[1]**2) / 2
      ang = math.atan2(self.dims[1]/2, self.dims[0]/2)
      start = (int(self.startx + math.cos(self.angle + ang + math.pi) * diag),
               int(self.starty + math.sin(self.angle + ang + math.pi) * diag))
      if self.ship_dims[0] > 1:
         x_d = self.ship_dims[0]
      else:
         x_d = 1
      if self.ship_dims[1] > 1:
         y_d = self.ship_dims[1]
      else:
         y_d = 1
      x_s = self.dims[0] / x_d
      y_s = self.dims[1] / y_d
      x_space = (int(x_s * math.cos(self.angle)),
                 int(x_s * math.sin(self.angle)))
      y_space = (-1 * int(y_s * math.sin(self.angle)),
                 int(y_s * math.cos(self.angle)))
      for i in range(0, self.ship_dims[0]):
         for j in range(0, self.ship_dims[1]):
            if j % 2 == 1:
               k = i + 0.5
            else:
               k = i
            p = (start[0] + int(k * x_space[0]) + j * y_space[0],
                 start[1] + int(k * x_space[1]) + j * y_space[1])
            Ship.spawn(self.ship_type, p, (p[0] + self.delx, p[1] + self.dely),
                       self.move_behavior, self.fire_behavior, **self.ship_args)

class sequential(Formation):
   __slots__ = ('spawn_interval',)
   
   def __init__(self, spawn_interval, **args):
      Configurable.Configurable.__init__(self, locals())
      Formation.__init__(self, **args)
      self.spawn_interval = spawn_interval
   
   def spawn(self):
      def s():
         self.spawn_real()
      spawner = Util.Delayed_Action(s, self.spawn_interval, self.count)
      spawner.start()
      
   def spawn_real(self):
      Ship.spawn(self.ship_type, (self.startx, self.starty), 
                        (self.destx, self.desty), self.move_behavior,
                        self.fire_behavior, **self.ship_args)

class single(Formation):
   def __init__(self, **args):
      Configurable.Configurable.__init__(self, locals())
      Formation.__init__(self, count=1, **args)
   
   def spawn(self):
      Ship.spawn(self.ship_type, (self.startx, self.starty), 
                        (self.destx, self.desty), self.move_behavior,
                        self.fire_behavior, **self.ship_args)
